/*
 * Copyright (C) 2004-2005, Universidade Federal de Campina Grande. All rights reserved.
 */
package org.epanetgrid.otimizacao.ag;

import java.io.Serializable;

/**
 * Classe com implementa��o default do fitness que � atribuido aos invid�duos em otimiza��es monoobjetivo
 * @author Vin�cius Ferraz Campos, vinicius.ferraz@gmail.com
 *
 */
public class SPFitness implements Serializable, SimpleFitness {
	private int severidade;
	private int intervaloDeErro;
	private double custo;
	private int tipoDeMutacao;

	/**
	 * Contrutor para um indiv�duo vi�vel, sem alarmes.
	 * @param Custo da fun��o monoObjetivo
	 */
	public SPFitness(double custo) {
		if (0 > custo) {
			throw new IllegalArgumentException("O custo deve ter valor maior que zero");
		}
		this.custo = custo;
		intervaloDeErro = -1;
		severidade = -1;
		tipoDeMutacao = 0;
	}

	/**
	 * 
	 * @param custo Custo da fun��o monoObjetivo
	 * @param erro Intervalo onde ocorreu o primeiro erro, -1 caso n�o exista erro
	 * @param severidade Severidade do alarme ocorrido, -2 se n�o tem alarme
	 * @param tipoDeMutacao Tipo de muta��o a ser efetuado para "corrigir" o alarme
	 */
	public SPFitness(double custo, int erro, int severidade, int tipoDeMutacao) {
		
		if (0 > custo) {
			throw new IllegalArgumentException("O custo deve ter valor maior que zero");
		}
		if (0 > erro) {
			throw new IllegalArgumentException();
		}
		if (0 > severidade) {
			throw new IllegalArgumentException();
		}
		if (0 >= tipoDeMutacao && -1 != tipoDeMutacao) {
			throw new IllegalArgumentException();
		}
		this.custo = custo;
		this.intervaloDeErro = erro;
		this.severidade = severidade;
		this.tipoDeMutacao = tipoDeMutacao;
	}

	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.ag.SimpleFitness#getCusto()
	 */
	public double getCusto() {
		return custo;
	}

	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.ag.SimpleFitness#getIntervaloDeErro()
	 */
	public int getIntervaloDeErro() {
		return intervaloDeErro;
	}

	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.ag.SimpleFitness#getSeveridade()
	 */
	public int getSeveridade() {
		return severidade;
	}

	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.ag.SimpleFitness#getTipoDeMutacao()
	 */
	public int getTipoDeMutacao() {
		return tipoDeMutacao;
	}

	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.ag.SimpleFitness#compareTo(java.lang.Object)
	 */
	public int compareTo(Object o) {
		if (!(o instanceof SPFitness)) {
			if (null == o) {
				throw new NullPointerException();
			}
			throw new ClassCastException();
		}
		SPFitness otherFit = (SPFitness) o;

        int result = comparaIntervalo(intervaloDeErro, otherFit.intervaloDeErro);
		if (result == 0) {
			result = comparaSeveridade(severidade, otherFit.severidade);
			if (result == 0) {
				return comparaCusto(custo, otherFit.custo);
			}
		}
		return result;
	}

    /**
     * Faz comparaceo entre duas severidades
     *
     * @param a
     * @param b
     * @return retorna < que 0 caso "a" seja maior, > 0 caso contr�rio 
     */
    private int comparaSeveridade(int a, int b) {
    	if (a == -1 || b == -1) {
    		if (a < b) {
    			return 1;
    		}
    		if (b < a) {
    			return -1;
    		}
    	}
		return b - a;
	}

	/**
     *
     *	Faz compara��o dos intervalos de erro
     *
     * @param a
     * @param b
     * @return retorna < que 0 caso "a" seja maior, > 0 caso contr�rio 
     */
    private static int comparaIntervalo(int a, int b) {
        if (a == -1 || b == -1) {
            // 1st n�o tem erro e 2nd tem 
            if (a < b) {
                return 1;
            }
            // 1st tem erro e 2nd n�o
            if (a > b) {
                return -1;
            }
        } else {
            // ambos contem erro, mas a � antes de b
            if (a < b) {
                return -1;
            }
            // ambos contem erro, mas a � depois de b
            if (a > b) {
                return 1;
            }
        }
        // quando s�o iguais.
        return 0;
    }

	/**
     * Faz compara��o dos custos
     *
	 * @param a
	 * @param b
	 * @return retorna < que 0 caso "a" seja maior, > 0 caso contr�rio 
	 */
	private static int comparaCusto(double a, double b) {
        // custo do 1st menor que do segundo
	    if (a < b) {
	        return 1;
	    }
        // custo do 1st maior que do segundo
	    if (a > b) {
	        return -1;
	    }
        // mesmo custo
	    return 0;
	}

	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.ag.SimpleFitness#toDouble()
	 */
	public double toDouble() {
		return getCusto();
	}

	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.ag.SimpleFitness#toString()
	 */
	public String toString() {
		return "Custo: " + custo + "; Intervalo: " + intervaloDeErro + "; Severidade: " + severidade + "; TipoMuta��o: " + tipoDeMutacao;
	}

}
